#include "system_memory_monitor.h"
#include <fstream>
#include <chrono>
#include <thread>
#include <unistd.h>
#include <sys/sysinfo.h>
#include <string>
#include <regex>
#include <sstream>

namespace El {
namespace SystemService {

MemoryMonitor &MemoryMonitor::GetInstance()
{
    static MemoryMonitor instance;
    return instance;
}

void MemoryMonitor::Start()
{
    if (running_) {
        return;
    }

    // 设置较低的OOM优先级（-300），保护重要应用不被轻易杀死
    if (!SetOOMAdjustment(-300)) {
        EL_WARN("设置OOM优先级失败，进程可能会在内存紧张时被系统终止");
    }

    // 设置较低的OOM阈值，提前预警
    SetOOMScoreThreshold(900);

    running_ = true;
    monitor_thread_ = std::thread(&MemoryMonitor::MonitorThread, this);
}

void MemoryMonitor::Stop()
{
    if (!running_) {
        return;
    }

    running_ = false;
    if (monitor_thread_.joinable()) {
        monitor_thread_.join();
    }
}

MemoryMonitor::~MemoryMonitor()
{
    Stop();
}

void MemoryMonitor::SetWarningThresholds(uint32_t warning_percent, uint32_t critical_percent)
{
    if (warning_percent >= critical_percent) {
        EL_WARN("警告阈值({})不能大于或等于严重阈值({}), 使用默认值", warning_percent, critical_percent);
        warning_percent_ = 70;
        critical_percent_ = 85;
        return;
    }
    warning_percent_ = warning_percent;
    critical_percent_ = critical_percent;
}

MemoryMonitor::WarningLevel MemoryMonitor::GetCurrentWarningLevel() const
{
    return current_level_.load();
}

MemoryMonitor::WarningLevel MemoryMonitor::CheckWarningLevel(const SystemMemoryInfo &sysInfo) const
{
    if (sysInfo.total_ram == 0) {
        return WarningLevel::NORMAL;
    }

    // 使用可用内存（包括可回收的缓存）来计算使用率
    uint64_t real_used = sysInfo.total_ram - sysInfo.available_ram;
    uint32_t usage_percent = static_cast<uint32_t>(real_used * 100 / sysInfo.total_ram);

    if (usage_percent >= critical_percent_) {
        return WarningLevel::CRITICAL;
    } else if (usage_percent >= warning_percent_) {
        return WarningLevel::WARNING;
    }

    return WarningLevel::NORMAL;
}

void MemoryMonitor::SetOOMScoreThreshold(int32_t threshold)
{
    oom_score_threshold_ = threshold;
}

bool MemoryMonitor::SetOOMAdjustment(int32_t adj)
{
    if (adj < -1000 || adj > 1000) {
        EL_ERROR("OOM调整值{}超出范围[-1000,1000]", adj);
        return false;
    }

    std::ofstream oom_adj("/proc/self/oom_score_adj");
    if (!oom_adj.is_open()) {
        EL_ERROR("无法打开/proc/self/oom_score_adj文件");
        return false;
    }

    oom_adj << adj;
    oom_adj.close();

    if (!UpdateOOMInfo()) {
        EL_ERROR("更新OOM信息失败");
        return false;
    }

    EL_INFO("已设置进程OOM优先级为{}, 当前OOM分数为{}", adj, proc_info_.oom_score);
    return true;
}

bool MemoryMonitor::UpdateOOMInfo()
{
    // 读取OOM分数
    std::ifstream oom_score("/proc/self/oom_score");
    if (!oom_score.is_open()) {
        EL_ERROR("无法打开/proc/self/oom_score文件");
        return false;
    }
    oom_score >> proc_info_.oom_score;
    oom_score.close();

    // 读取OOM调整值
    std::ifstream oom_adj("/proc/self/oom_score_adj");
    if (!oom_adj.is_open()) {
        EL_ERROR("无法打开/proc/self/oom_score_adj文件");
        return false;
    }
    oom_adj >> proc_info_.oom_adj;
    oom_adj.close();

    return true;
}

MemoryMonitor::WarningLevel MemoryMonitor::CheckOOMRisk() const
{
    // 检查OOM风险
    if (proc_info_.oom_score >= oom_score_threshold_) {
        return WarningLevel::OOM_DANGER;
    }

    // 检查系统内存压力 - 对于小内存设备(<=40MB)，提高检查标准到15%
    if (sys_info_.total_ram <= 40) {                                // 40MB及以下的设备
        if (sys_info_.available_ram < sys_info_.total_ram * 0.15) { // 可用内存少于15%
            return WarningLevel::OOM_DANGER;
        }
    } else { // 大内存设备保持10%的阈值
        if (sys_info_.available_ram < sys_info_.total_ram * 0.10) {
            return WarningLevel::OOM_DANGER;
        }
    }

    return WarningLevel::NORMAL;
}

void MemoryMonitor::UpdateMemoryInfo()
{
    // 更新系统内存信息
    struct sysinfo si;
    if (sysinfo(&si) == 0) {
        const uint64_t kb = 1024;
        const uint64_t mb = kb * 1024;

        sys_info_.total_ram = si.totalram / mb;
        sys_info_.free_ram = si.freeram / mb;

        // 读取 /proc/meminfo 获取更详细的内存信息
        std::ifstream meminfo("/proc/meminfo");
        if (meminfo.is_open()) {
            std::string line;
            while (std::getline(meminfo, line)) {
                std::istringstream iss(line);
                std::string name;
                uint64_t value;

                if (line.find("Cached:") == 0) {
                    iss >> name >> value;
                    sys_info_.cached_ram = value / 1024; // KB to MB
                } else if (line.find("Buffers:") == 0) {
                    iss >> name >> value;
                    sys_info_.buffers_ram = value / 1024; // KB to MB
                } else if (line.find("MemAvailable:") == 0) {
                    iss >> name >> value;
                    sys_info_.available_ram = value / 1024; // KB to MB
                }
            }
        }

        // 计算实际使用的内存（使用MemAvailable更准确）
        sys_info_.used_ram = sys_info_.total_ram - sys_info_.available_ram;
    }

    // 更新进程内存信息
    std::ifstream status_file("/proc/self/status");
    if (status_file.is_open()) {
        std::string line;
        while (std::getline(status_file, line)) {
            std::istringstream iss(line);
            std::string name;
            uint64_t value;

            if (line.find("VmRSS:") == 0) {
                iss >> name >> value;
                proc_info_.vm_rss = value / 1024; // KB to MB
            } else if (line.find("VmHWM:") == 0) {
                iss >> name >> value;
                proc_info_.vm_hwm = value / 1024; // KB to MB
            }
        }
    }

    // 尝试读取 /proc/self/smaps 获取 PSS 信息
    uint64_t total_pss = 0;
    std::ifstream smaps("/proc/self/smaps");
    if (smaps.is_open()) {
        std::string line;
        while (std::getline(smaps, line)) {
            std::istringstream iss(line);
            std::string name;
            uint64_t value;

            if (line.find("Pss:") == 0) {
                iss >> name >> value;
                total_pss += value;
            }
        }
        proc_info_.vm_pss = total_pss / 1024; // KB to MB
    }

    // 更新OOM相关信息
    UpdateOOMInfo();
}

SystemMemoryInfo MemoryMonitor::GetSystemMemoryInfo() const
{
    return sys_info_;
}

ProcessMemoryInfo MemoryMonitor::GetProcessMemoryInfo() const
{
    return proc_info_;
}

void MemoryMonitor::MonitorThread()
{
    while (running_) {
        UpdateMemoryInfo();

        // 检查OOM风险
        WarningLevel oom_level = CheckOOMRisk();

        // 检查内存使用告警级别
        WarningLevel mem_level = CheckWarningLevel(sys_info_);

        // 使用较高的告警级别
        WarningLevel level = std::max(oom_level, mem_level);
        current_level_.store(level);

        // 计算实际物理内存使用率
        uint32_t usage_percent =
            sys_info_.total_ram > 0 ? static_cast<uint32_t>(sys_info_.used_ram * 100 / sys_info_.total_ram) : 0;

        // 根据不同告警级别输出日志
        switch (level) {
            case WarningLevel::OOM_DANGER:
                EL_ERROR(
                    "内存压力警告: 进程OOM分数 {} (优先级 {}), 系统内存使用率 {}%, 可用内存 {} MB\n"
                    "           建议操作: 1)检查内存泄漏 2)减少内存使用 3)保存重要数据",
                    proc_info_.oom_score, proc_info_.oom_adj, usage_percent, sys_info_.available_ram);
                break;
            case WarningLevel::CRITICAL:
                EL_ERROR("系统内存使用严重: 总内存 {} MB, 已用 {} MB ({}%), 可用 {} MB, 缓存/缓冲 {} MB",
                          sys_info_.total_ram, sys_info_.used_ram, usage_percent, sys_info_.available_ram,
                          sys_info_.cached_ram + sys_info_.buffers_ram);
                break;
            case WarningLevel::WARNING:
                EL_WARN("系统内存使用警告: 总内存 {} MB, 已用 {} MB ({}%), 可用 {} MB, 缓存/缓冲 {} MB",
                         sys_info_.total_ram, sys_info_.used_ram, usage_percent, sys_info_.available_ram,
                         sys_info_.cached_ram + sys_info_.buffers_ram);
                break;
            default:
                EL_DEBUG(
                    "内存使用情况 - 系统: 总内存 {} MB, 已用 {} MB ({}%), 可用 {} MB\n"
                    "           缓存/缓冲: {} MB\n"
                    "           本进程: 物理内存 {} MB (PSS {} MB), OOM分数 {} (优先级 {})",
                    sys_info_.total_ram, sys_info_.used_ram, usage_percent, sys_info_.available_ram,
                    sys_info_.cached_ram + sys_info_.buffers_ram, proc_info_.vm_rss, proc_info_.vm_pss,
                    proc_info_.oom_score, proc_info_.oom_adj);
                break;
        }

        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

} // namespace SystemService
} // namespace El